﻿using System;
using System.IO;
using System.Text;
using System.Linq;
using System.Windows;
using System.ComponentModel;
using System.Xml.Serialization;
using Cratos.Desktop.Persistence;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Runtime.Serialization.Formatters.Binary;

using Microsoft.Practices.Unity;

using Cratos.Tools.General;

namespace Cratos.Tools.DataObject
{
	/// <summary>
	/// Cratos Data Object Paging Collection class
	/// </summary>
	/// <typeparam name="T"></typeparam>
	[Serializable]
	public class DOCratosPagingCollection<T> : BindingList<T>, IDisposable, IDOCratosPagingCollection<T>, INotifyPropertyChanged where T : IDOCratos, new()
	{
		#region Class Constant declarations
		#endregion

		#region Class Event declarations
		/// <summary>
		/// Entity New Page event
		/// </summary>
		[field: NonSerialized]
		public event CollectionNewPageEventHandler NewPage;

		/// <summary>
		/// Entity Error event
		/// </summary>
		[field: NonSerialized]
		public event CollectionErrorEventHandler Error;

		/// <summary>
		/// Entity Completed event
		/// </summary>
		[field: NonSerialized]
		public event CollectionCompletedEventHandler Completed;

		/// <summary>
		/// Property Changed event
		/// </summary>
		[field: NonSerialized]
		public event PropertyChangedEventHandler PropertyChanged;
		#endregion

		#region Class Variable declarations
		private bool																										isDisposed;
		private long																										pageCount        = 0;
		private long																										recordCount      = 0;
		private DOCratosCollectionAction																collectionAction = DOCratosCollectionAction.None;

		private Collection<CratosError>																	doErrors = new Collection<CratosError>();
		private Collection<DOCratosActionAttribute>											doActions;
		private Dictionary<DOCratosCollectionAction, List<CratosRule>>	currentRules;

		[field: NonSerialized]
		private CratosPersistence doPersistence;
		#endregion

		#region Class Constructors & Destructors
		/// <summary>
		/// Class Constructor
		/// </summary>
		public DOCratosPagingCollection() : base()
		{
			// Set the relevant default properties
			this.DOGuid                 = Guid.NewGuid();
			this.CollectionActionResult = DOCratosActionResult.None;
			this.CollectionActionName   = "";
			this.CollectionAction       = DOCratosCollectionAction.None;
			this.IsCacheRetrieve        = false;

			this.IsClientSide		   = true;
			this.PagingEnabled	   = DOCratosGlobal.PagingEnabled;
			this.MaxNoRecords      = DOCratosGlobal.PagingMaxNoRecords;
			this.PersistCollection = DOCratosGlobal.PagingPersistCollection;

			// Create and Setup the Persistence
			this.doPersistence                    = new CratosPersistence();
			this.doPersistence.DBConnectionString = DOCratosGlobal.PagingDBConnectionString;

			// Create and Setup the relevant object(s)
			this.DataObject                  = new T();
			this.DataObject.DBConnectionName = DOCratosGlobal.DBConnectionName;
			this.DataObject.DBActionType     = DOCratosActionType.StoredProcedure;
		}

		/// <summary>
		/// Performs application-defined tasks associated with freeing, releasing, or
		/// resetting unmanaged resources.
		/// </summary>
		public void Dispose() { Dispose(true); GC.SuppressFinalize(this); }

		/// <summary>
		/// Dispose method doing the disposing
		/// </summary>
		/// <param name="isDisposing"></param>
		protected virtual void Dispose(bool isDisposing)
		{
			// Declare the required variables

			// Check to see if Dispose has already been called.
			if (!this.isDisposed)
			{
				// Dispose the objects if required
				if (isDisposing)
				{
				}
			}

			// Set the disposed indicator
			this.isDisposed = true;

			// Return to calling method
			return;
		}
		#endregion

		#region Class Properties
		/// <summary>
		/// DO Collection GUID
		/// </summary>
		public Guid DOGuid { get; set; }

		/// <summary>
		/// Ignore Unity Indicator
		/// </summary>
		public bool IgnoreUnity { get; set; }

		/// <summary>
		/// Data Object List Action Result
		/// </summary>
		public DOCratosActionResult CollectionActionResult { get; set; }

		/// <summary>
		/// Data Object Action Name
		/// </summary>
		public string CollectionActionName { get; set; }

		/// <summary>
		/// Collection of Errors
		/// </summary>
		public Collection<CratosError> Errors
		{
			get { return (this.doErrors); }
		}

		/// <summary>
		/// Cache Retrieve indicator
		/// </summary>
		public bool IsCacheRetrieve { get; set; }

		/// <summary>
		/// Cratos Data Object Actions
		/// </summary>
		[XmlIgnore]
		public Collection<DOCratosActionAttribute> AllDOActions
		{
			get
			{
				// Declare the required variables

				// Make sure we have an object to work with
				if (this.doActions == null)
				{
					// Create the relevant object
					this.doActions = new Collection<DOCratosActionAttribute>();

					// Retrieve all the Cratos Actions associated with the class
					DOCratosActionAttribute[] allActions = (DOCratosActionAttribute[])this.GetType().GetCustomAttributes(typeof(DOCratosActionAttribute), false);

					// Make sure we have data to work with
					if (allActions != null)
					{
						foreach (DOCratosActionAttribute currentAction in allActions)
						{
							if (currentAction.CratosCollectionAction != DOCratosCollectionAction.None) { this.doActions.Add(currentAction); }
						}
					}
				}

				// Return to calling method
				return (this.doActions);
			}
		}

		/// <summary>
		/// Data Object List Action
		/// </summary>
		public DOCratosCollectionAction CollectionAction
		{
			get { return (this.collectionAction); }
			set
			{
				// Save the new value
				this.collectionAction = value;

				// Update the DB Connection Name if required
				foreach (DOCratosActionAttribute currentAction in this.AllDOActions)
				{
					// Make sure the Connection Name is specified
					if (!string.IsNullOrEmpty(currentAction.DBConnectionName))
					{
						switch (this.collectionAction)
						{
							case DOCratosCollectionAction.Retrieve:
								if ((currentAction.CratosCollectionAction == this.collectionAction) &&
										(currentAction.CratosActionType == this.DataObject.DBActionType))
								{
									this.DataObject.DBConnectionName = currentAction.DBConnectionName;
								}
								break;
						}
					}
				}
			}
		}

		/// <summary>
		/// Error Message
		/// </summary>
		[XmlIgnore]
		public string ErrorMessage
		{
			get
			{
				// Declare the required variables
				StringBuilder returnValue = new StringBuilder();

				// Make sure we have errors
				if (this.Errors.Count > 0)
				{
					// Process all the errors
					foreach (CratosError currentError in this.Errors)
					{
						if (currentError.RuntimeException == null)
						{
							returnValue.AppendLine(string.Format("[{0}-{1}] [{2}] {3}", currentError.Date.ToString("dd/MM/yyyy HH:mm:ss"),
																																					currentError.Source,
																																					currentError.Severity.ToString(),
																																					currentError.Message));
						}
						else
						{
							returnValue.AppendLine(string.Format("[{0}-{1}] [{2}] {3}", currentError.Date.ToString("dd/MM/yyyy HH:mm:ss"),
																																					currentError.Source,
																																					currentError.Severity.ToString(),
																																					currentError.Message + "\n" + currentError.RuntimeException.ToString()));
						}
					}
				}
				else { returnValue.AppendLine("No errors found"); }

				// Return to calling method
				return (returnValue.ToString());
			}
		}

		/// <summary>
		/// Client Side indicator
		/// </summary>
		public bool IsClientSide { get; set; }

		/// <summary>
		/// Raptor Data Object
		/// </summary>
		public T DataObject { get; set; }

		/// <summary>
		/// Paging Enabled indicator
		/// </summary>
		public bool PagingEnabled { get; set; }

		/// <summary>
		/// Max No of records per Page
		/// </summary>
		public long MaxNoRecords { get; set; }

		/// <summary>
		/// Overall Record Count
		/// </summary>
		public long RecordCount
		{
			get { return (this.recordCount); }
			set { this.recordCount = value; this.NotifyPropertyChanged("RecordCount"); }
		}

		/// <summary>
		/// Overall Page Count
		/// </summary>
		public long PageCount
		{
			get { return (this.pageCount); }
			set { this.pageCount = value; this.NotifyPropertyChanged("PageCount"); }
		}

		/// <summary>
		/// Current Page Number
		/// </summary>
		public long CurrentPage { get; set; }

		/// <summary>
		/// Persist the relevant collection
		/// </summary>
		public bool PersistCollection { get; set; }
		#endregion

		#region Class Operators
		/// <summary>
		/// Cast from List of IDOCratos to DOCratosCollection of T
		/// </summary>
		/// <param name="doList">Incoming DO List</param>
		/// <returns>The new Collection</returns>
		public static explicit operator DOCratosPagingCollection<T>(List<T> doList)
		{
			// Declare the required variables
			DOCratosPagingCollection<T> returnCollection;

			// Create the return collection
			returnCollection = new DOCratosPagingCollection<T>();

			// Process all the items in the incoming list
			foreach (T item in doList)
			{
				if (item is T) { returnCollection.Add((T)item); }
				else
				{
					throw new InvalidCastException(string.Format("Cannot cast {0} as {1}.", item.GetType(), typeof(T)));
				}
			}

			// Return to calling method
			return (returnCollection);
		}

		/// <summary>
		/// Cast from List of IDOCratos to DOCratosCollection of T
		/// </summary>
		/// <param name="doList">Incoming DO List</param>
		/// <returns>The new Collection</returns>
		public static explicit operator List<T>(DOCratosPagingCollection<T> doList)
		{
			// Declare the required variables
			List<T> returnCollection;

			// Create the return collection
			returnCollection = new List<T>();

			// Process all the items in the incoming list
			foreach (T item in doList)
			{
				if (item is T) { returnCollection.Add((T)item); }
				else
				{
					throw new InvalidCastException(string.Format("Cannot cast {0} as {1}.", item.GetType(), typeof(T)));
				}
			}

			// Return to calling method
			return (returnCollection);
		}
		#endregion

		#region Class Methods
		/// <summary>
		/// Create a new copy of the object
		/// </summary>
		/// <returns>A new cloned object</returns>
		public virtual object Clone()
		{
			// Return to calling method
			return (DOCratosGlobal.CloneObject(this));
		}

		/// <summary>
		/// Perform the specified Action
		/// </summary>
		/// <returns>A boolean indicating the success of the method</returns>
		public virtual bool PerformAction()
		{
			// Declare the required variables
			bool																		returnValue  = false;
			ICratosEntityPagingCollectionAccess<T>	entityAccess = null;

			try
			{
				// Clear any pending errors
				this.Errors.Clear();

				// Retrieve the Entity Access object
				entityAccess = this.GetEntityAccess();

				// Make sure we have an Entity object to work with
				if (entityAccess != null)
				{
					// Subscribe to the relevant event(s)
					entityAccess.NewPage   += new EntityCollectionNewPageEventHandler(this.OnEntityAccessNewPage);
					entityAccess.Error     += new EntityCollectionErrorEventHandler(this.OnEntityAccessError);
					entityAccess.Completed += new EntityCollectionCompletedEventHandler(this.OnEntityAccessCompleted);

					// Execute the relevant Action
					if (entityAccess.PerformAction((IDOCratosPagingCollection<T>)this)) { returnValue = true; }
					else
					{
						foreach (CratosError currentError in entityAccess.Errors) { this.Errors.Add(currentError); }
					}
				}
				else { throw new Exception("Failed to create the required Cratos Collection Access Type"); }
			}
			catch (Exception runtimeException)
			{
				// Create and setup a new error
				this.Errors.Add(new CratosError("DOCratosCollection.PerformAction", CratosLogSeverity.Exception,
																				"Runtime error ocurred", runtimeException));
			}
			finally
			{
				// Raise the error event if required
				if (this.Errors.Count > 0) { this.OnEntityAccessError(this.Errors); }
			}

			// Return to calling method
			return (returnValue);
		}

		/// <summary>
		/// Validate the object against the current action
		/// </summary>
		/// <returns></returns>
		public virtual bool Validate()
		{
			// Declare the required variables

			// Clear any pending errors
			this.Errors.Clear();

			// Handle the Collection Action
			switch (this.CollectionAction)
			{
				case DOCratosCollectionAction.Retrieve:
				case DOCratosCollectionAction.Custom:
					// Validate the Data Object
					if (!this.DataObject.Validate())
					{
						// Add the relevant errors to the current collection
						foreach (CratosError currentError in this.DataObject.Errors) { this.Errors.Add(currentError); }
					}

					break;

				case DOCratosCollectionAction.Various:
					// Process all the items in the collection
					foreach (IDOCratos currentItem in this)
					{
						if (!currentItem.Validate())
						{
							// Add the relevant errors to the current collection
							foreach (CratosError currentError in currentItem.Errors) { this.Errors.Add(currentError); }
						}
					}
					break;
			}

			// Return to calling method
			return (this.Errors.Count <= 0);
		}

		#region Paging Methods
		/// <summary>
		/// Load the First Page
		/// </summary>
		/// <returns>A boolean indicating the success of the method</returns>
		public bool FirstPage()
		{
			// Declare the required variables
			bool returnValue = false;

			// Make sure the persistence if enabled
			if ((this.PersistCollection) || (this.CurrentPage == 1))
			{
				// Clear all current collection data
				this.Clear();

				// Make sure we have records
				if (this.PageCount >= 1)
				{
					// Update the Current Page
					this.CurrentPage = 1;

					// Load the Page
					returnValue = this.GotoPage(this.CurrentPage);
				}
			}
			else { returnValue = true; }

			// return to calling method
			return(returnValue);
		}

		/// <summary>
		/// Load the Previous Page
		/// </summary>
		/// <returns>A boolean indicating the success of the method</returns>
		public bool PreviousPage()
		{
			// Declare the required variables
			bool returnValue = false;

			// Make sure the persistence if enabled
			if ((this.PersistCollection) || (this.CurrentPage > 1))
			{
				// Clear all current collection data
				this.Clear();

				// Update the Current Page
				this.CurrentPage--;

				// Load the Page
				returnValue = this.GotoPage(this.CurrentPage);
			}
			else { returnValue = true; }

			// return to calling method
			return (returnValue);
		}

		/// <summary>
		/// Load the Next Page
		/// </summary>
		/// <returns>A boolean indicating the success of the method</returns>
		public bool NextPage()
		{
			// Declare the required variables
			bool returnValue = false;

			// Make sure the persistence if enabled
			if ((this.PersistCollection) || (this.PageCount < this.CurrentPage))
			{
				// Clear all current collection data
				this.Clear();

				// Update the Current Page
				this.CurrentPage++;

				// Load the Page
				returnValue = this.GotoPage(this.CurrentPage);
			}
			else { returnValue = true; }

			// return to calling method
			return (returnValue);
		}

		/// <summary>
		/// Load the Last Page
		/// </summary>
		/// <returns>A boolean indicating the success of the method</returns>
		public bool LastPage()
		{
			// Declare the required variables
			bool returnValue = false;

			// Make sure the persistence if enabled
			if ((this.PersistCollection) || (this.CurrentPage < this.PageCount))
			{
				// Clear all current collection data
				this.Clear();

				// Update the Current Page
				this.CurrentPage = this.PageCount;

				// Load the Page
				returnValue = this.GotoPage(this.CurrentPage);
			}
			else { returnValue = true; }

			// return to calling method
			return (returnValue);
		}

		/// <summary>
		/// Load a specified page
		/// </summary>
		/// <param name="pageNo">Page to load</param>
		/// <returns>A boolean indicating the success of the method</returns>
		public bool GotoPage(long pageNo)
		{
			// Declare the required variables
			bool					returnValue = false;
			Collection<T> pageData;

			// Make sure the persistence if enabled
			if ((this.PersistCollection) || (this.CurrentPage > 0))
			{
				// Clear all current collection data
				this.Clear();

				// Make sure we have records
				if (pageNo <= this.PageCount)
				{
					// Persist the collection to the DB
					pageData = this.doPersistence.DBRetrievePagingCollection<T>(this.DOGuid, pageNo);

					// Process all the returned data
					foreach (T currentItem in pageData) { this.Add(currentItem); }
				}
			}
			else { returnValue = true; }

			// return to calling method
			return (returnValue);
		}
		#endregion

		#region Rule Methods
		/// <summary>
		/// Initialize the DO Rules
		/// </summary>
		public virtual void InitializeRules()
		{
			// Declare the required variables

			// Creat a new Rule object if required
			if (this.currentRules == null) { this.currentRules = new Dictionary<DOCratosCollectionAction, List<CratosRule>>(); }

			// Clear all current Rules
			this.currentRules.Clear();

			// Return to calling method
			return;
		}

		/// <summary>
		/// Add Custom Rule to Data Object Validation
		/// </summary>
		/// <param name="collectionAction">Cratos Collection Action</param>
		/// <param name="newRule">New Cratos Rule</param>
		public void AddRule(DOCratosCollectionAction collectionAction, CratosRule newRule)
		{
			// Declare the required variables
			List<CratosRule> newRuleList;

			// Add the Rule appropriately
			if (this.currentRules.ContainsKey(collectionAction))
			{
				// Add the Rule to the Rule List
				this.currentRules[collectionAction].Add(newRule);
			}
			else
			{
				// Create the Rule List and add the Cratos Rule
				newRuleList = new List<CratosRule>();
				newRuleList.Add(newRule);

				// Add the item to the Rule Dictionary
				this.currentRules.Add(collectionAction, newRuleList);
			}

			// Return to calling method
			return;
		}

		/// <summary>
		/// Validate all the relevant Rules
		/// </summary>
		/// <param name="collectionAction">Cratos Collection Action</param>
		/// <returns>A boolean indicating the success of the method</returns>
		public bool ValidateRules(DOCratosCollectionAction collectionAction)
		{
			// Declare the required variables
			bool returnValue = true;
			List<CratosRule> actionRules;

			try
			{
				// Make sure we have Rules for the associated Action
				if ((this.currentRules != null) && (this.currentRules.ContainsKey(collectionAction)))
				{
					// Retrieve the Action rules
					actionRules = this.currentRules[collectionAction];

					// Process all the Rules
					foreach (CratosRule currentRule in actionRules)
					{
						if (!currentRule.IsValid)
						{
							this.Errors.Add(new CratosError("Validation Rules", CratosLogSeverity.ValidationError, currentRule.Description));
							returnValue = false;
						}
					}
				}
			}
			catch (Exception runtimeException)
			{
				// Create and setup a new error
				this.Errors.Add(new CratosError("DOCratosCollection.ValidateRules", CratosLogSeverity.Exception,
																				"Runtime error ocurred", runtimeException));
			}

			// Return to calling method
			return (returnValue);
		}
		#endregion

		/// <summary>
		/// Display the current Errors in the error collection
		/// </summary>
		/// <param name="appTitle">Application Title</param>
		public virtual void DisplayError(string appTitle)
		{
			// Declare the required variables
			StringBuilder errorMessage;

			// Build the error message
			errorMessage = new StringBuilder();
			foreach (CratosError currentError in this.Errors)
			{
				if (currentError.RuntimeException == null)
				{
					errorMessage.AppendLine(string.Format("[{0} - {1}] [{2}] {3}", currentError.Date.ToString("dd/MM/yyyy HH:mm:ss"),
																																				 currentError.Source,
																																				 currentError.Severity.ToString(),
																																				 currentError.Message));
				}
				else
				{
					errorMessage.AppendLine(string.Format("[{0} - {1}] [{2}] {3}\n{4}", currentError.Date.ToString("dd/MM/yyyy HH:mm:ss"),
																																							currentError.Source,
																																							currentError.Severity.ToString(),
																																							currentError.Message,
																																							currentError.RuntimeException.ToString()));
				}
			}

			// Display the error to the user
			MessageBox.Show(errorMessage.ToString(), appTitle, MessageBoxButton.OK, MessageBoxImage.Error, MessageBoxResult.OK);

			// Return to calling method
			return;
		}

		/// <summary>
		/// Display the current Errors in the error collection
		/// </summary>
		/// <param name="appTitle">Application Title</param>
		public void DisplayValidation(string appTitle)
		{
			// Declare the required variables
			StringBuilder errorMessage;

			// Build the error message
			errorMessage = new StringBuilder();
			foreach (CratosError currentError in this.Errors)
			{
				if (currentError.RuntimeException == null)
				{
					errorMessage.AppendLine(currentError.Message);
				}
				else
				{
					errorMessage.AppendLine(string.Format("[{0} - {1}] [{2}] {3}\n{4}", currentError.Date.ToString("dd/MM/yyyy HH:mm:ss"),
																																							currentError.Source,
																																							currentError.Severity.ToString(),
																																							currentError.Message,
																																							currentError.RuntimeException.ToString()));
				}
				errorMessage.AppendLine();
			}

			// Display the error to the user
			MessageBox.Show(errorMessage.ToString(), appTitle, MessageBoxButton.OK, MessageBoxImage.Information, MessageBoxResult.OK);

			// Return to calling method
			return;
		}

		/// <summary>
		/// Retrieve the Collection
		/// </summary>
		/// <returns></returns>
		public Collection<IDOCratos> GetCollection()
		{
			// Declare the required variables
			Collection<IDOCratos> returnValue;

			// Create the new List
			returnValue = new Collection<IDOCratos>();

			// Process all the relevant items
			foreach (IDOCratos currentItem in this) { returnValue.Add(currentItem); }

			// Return to calling method
			return (returnValue);
		}

		/// <summary>
		/// Retrieve the List
		/// </summary>
		/// <returns></returns>
		public List<IDOCratos> GetList()
		{
			// Declare the required variables
			List<IDOCratos> returnValue;

			// Create the new List
			returnValue = new List<IDOCratos>();

			// Process all the relevant items
			foreach (IDOCratos currentItem in this) { returnValue.Add(currentItem); }

			// Return to calling method
			return (returnValue);
		}

		/// <summary>
		/// String Representation of the object
		/// </summary>
		/// <returns>String Representation</returns>
		public override string ToString()
		{
			// Declare the required variables
			StringBuilder returnValue;

			// Make sure we have data to work with
			if (this.Count <= 0) { return ("No Items"); }
			else
			{
				// Create the String Builder
				returnValue = new StringBuilder();

				// Process all the items in the list
				foreach (T currentItem in this.OrderBy<T, string>(item => item.ToString()))
				{
					returnValue.AppendFormat("{0},", currentItem.ToString());
				}
			}

			// Return to calling method
			return (returnValue.ToString().Substring(0, (returnValue.ToString().Length - 1)));
		}

		/// <summary>
		/// Notify Property Changed method
		/// </summary>
		/// <param name="changeInfo">Change information</param>
		protected virtual void NotifyPropertyChanged(string changeInfo)
		{
			// Declare the required variables

			// Make sure we have somebody listening
			if (this.PropertyChanged != null)
			{
				// Raise the Property Changed event
				this.PropertyChanged(this, new PropertyChangedEventArgs(changeInfo));
			}

			// Return to calling method
			return;
		}

		/// <summary>
		/// Create Serialize Stream from object
		/// </summary>
		/// <returns>
		/// A byte array of the serialized object
		/// </returns>
		public virtual byte[] CreateSerializeStream()
		{
			// Return to calling method
			return (DOCratosGlobal.BinSerialize(this));
		}

		/// <summary>
		/// Create Object from a Serialized object
		/// </summary>
		/// <param name="objectStream">A byte array representing the serialized object</param>
		/// <returns>
		/// The recreated object
		/// </returns>
		public virtual object CreateObjectFromStream(byte[] objectStream)
		{
			// Throw an exception
			throw new NotImplementedException();
		}
		#endregion

		#region Class Support Methods
		private void OnEntityAccessNewPage(long pageNo, Collection<IDOCratos> doCollection)
		{
			// Declare the required variables

			// Handle the Client Side of the Collection
			if (this.IsClientSide)
			{
				// Update the relevant properties
				this.PageCount   = pageNo;
				this.RecordCount = this.RecordCount + doCollection.Count;

				// Handle the Persistence
				if (this.PersistCollection)
				{
					// Make sure we load the first page
					if (this.CurrentPage <= 0)
					{
						// Add the relevant objects to the collection
						foreach (IDOCratos currentItem in doCollection) { this.Add((T)currentItem); }
					}

					// Persist the collection to the DB
					this.doPersistence.DBAddPagingCollection(pageNo, this.DOGuid, doCollection, this.DataObject.AllDOProperties);
				}
				else
				{
					// Add the relevant objects to the collection
					foreach (IDOCratos currentItem in doCollection) { this.Add((T)currentItem); }
				}
			}

			// Raise the relevant event
			if (this.NewPage != null) { this.NewPage(pageNo, doCollection); }

			// Return to calling method
			return;
		}

		private void OnEntityAccessError(Collection<CratosError> errorCollection)
		{
			// Declare the required variables

			// Handle the Client Side of the Collection
			if (this.IsClientSide)
			{
				// Process all the errors
				foreach (CratosError currentError in errorCollection) { this.Errors.Add(currentError); }
			}

			// Raise the relevant event
			if (this.Error != null) { this.Error(errorCollection); }

			// Return to calling method
			return;
		}

		private void OnEntityAccessCompleted(DOCratosActionResult actionResult, Collection<IDOCratos> doCollection)
		{
			// Declare the required variables

			// Handle the Client Side of the Collection
			if (this.IsClientSide)
			{
				// Update the relevant properties
				this.PageCount	            = doCollection.Count > 0 ? ++this.PageCount : this.PageCount;
				this.RecordCount            = this.RecordCount + doCollection.Count;
				this.CollectionActionResult = actionResult;

				// Handle the Persistence
				if (this.PersistCollection)
				{
					// Persist the collection to the DB
					this.doPersistence.DBAddPagingCollection(this.PageCount, this.DOGuid, doCollection, this.DataObject.AllDOProperties);
				}
				else
				{
					// Add the relevant objects to the collection
					foreach (IDOCratos currentItem in doCollection) { this.Add((T)currentItem); }
				}
			}

			// Raise the relevant event
			if (this.Completed != null) { this.Completed(actionResult, doCollection); }

			// Return to calling method
			return;
		}

		private ICratosEntityPagingCollectionAccess<T> GetEntityAccess()
		{
			// Declare the required variables
			Type																		doType, doGenericType;
			ICratosEntityPagingCollectionAccess<T>	entityAccess = null;

			try
			{
				// Create the relevant type
				if (this.IgnoreUnity)
				{
					// Create the required Generic Type
					doType                   = Type.GetType("Cratos.Server.Entity.CratosEntityPagingCollection`1, Cratos.Server.Entity");
					doGenericType            = doType.MakeGenericType(new Type[] { this.DataObject.GetType() });
					entityAccess             = ((ICratosEntityPagingCollectionAccess<T>)Activator.CreateInstance(doGenericType));
					entityAccess.IgnoreUnity = true;
				}
				else
				{
					entityAccess = DOCratosGlobal.UnityContainer.Resolve<ICratosEntityPagingCollectionAccess<T>>(DOCratosGlobal.EntityPagingCollectionAccessMethod);
				}
			}
			catch (Exception runtimeException)
			{
				// Create and setup a new error
				this.Errors.Add(new CratosError("DOCratosCollection.PerformAction", CratosLogSeverity.Exception,
																				"Runtime error ocurred", runtimeException));
			}

			// Return to calling method
			return (entityAccess);
		}
		#endregion
	}
}
